package com.hframe.database;

import com.hframe.type.T;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * Created by heqian on 17-12-5.
 */
public class SqlTemplate extends T<String> {
    private Param param = null;

    public SqlTemplate() {
        super(String.class);
    }

    public SqlTemplate(String template) {
        super(template, String.class);
    }

    @Override
    public void set(String template) {
        param = null;
        super.set(template);
    }

    protected Param parse() throws SqlException {
        if (null == this.param) {
            LinkedList<Param> index = new LinkedList<>();
            char charAt = 0;
            char quote = 0;
            char backslash = 0;
            boolean mark = true;
            Param param = new Param(0, charAt);
            index.push(param);

            for (int i = 0; i < object.length(); i++) {
                charAt = object.charAt(i);
                if ('[' == charAt && mark) {
                    if (index.isEmpty() || '[' == index.getFirst().tag)
                        syntaxError(object, i, i + 1);

                    if (0 == i || '{' == object.charAt(i - 1))
                        syntaxError(object, i - 1, i + 1);

                    param.pointEnd = i;
                    param = new Param(i, '[');
                    index.getFirst().params.add(param);
                    index.push(param);
                } else if ('{' == charAt && mark) {
                    if (0 != i && ':' == object.charAt(i - 1))
                        syntaxError(object, i - 1, i + 1);

                    param = new Param(i, '{');
                    index.getFirst().params.add(param);
                    index.push(param);

                } else if ('}' == charAt && mark) {
                    if (index.isEmpty())
                        syntaxError(object, i, i + 1);

                    param = index.poll();
                    if ('{' != param.tag || i == param.start + 1 || i == param.point + 1)
                        syntaxError(object, param.start, i + 1);
                    param.end = i;
                } else if (']' == charAt && mark) {
                    if (index.isEmpty())
                        syntaxError(object, i, i + 1);

                    param = index.poll();
                    if ('[' != param.tag || i == param.start + 1)
                        syntaxError(object, param.start, i + 1);
                    param.end = i;
                } else if (':' == charAt && mark) {
                    if (!index.isEmpty()) {
                        param = index.getFirst();
                        if ('[' == param.tag || ('{' == param.tag && param.start + 1 == i))
                            syntaxError(object, param.start, i + 1);
                        param.point = i;
                    }
                } else if ('\'' == charAt && mark) {
                    mark = false;

                } else if ('\'' == charAt && !mark) {
                    mark = true;

                } else if ('\\' == charAt) {
                    backslash = '\\';
                    mark = false;

                } else if (backslash == charAt) {
                    backslash = 0;
                    mark = true;

                } else if ('`' == charAt && 0 == quote && mark) {
                    quote = '`';
                    param = new Param(i, '`');
                    index.getFirst().params.add(param);
                    index.push(param);

                } else if ('`' == charAt && '`' == quote && mark) {
                    quote = 0;
                    param = index.poll();
                    if ('`' != param.tag || i == param.start + 1)
                        syntaxError(object, param.start, i + 1);
                    param.end = i;
                }
            }

            if (1 < index.size()) {
                param = index.poll();
                throw new SqlException("书写错误：" + param.start + "  " + object.substring(param.start, object.length()));
            }

            param = index.poll();
            param.end = object.length();
            this.param = param;
        }
        return this.param;
    }

    protected void syntaxError(String sql, int start, int end) throws SqlException {
        throw new SqlException("书写错误：" + start + "  " + sql.substring(start, end));
    }

    protected class Param {
        int start = -1;
        int end = -1;
        char tag = 0;
        int point = -1;
        ArrayList<Param> params = new ArrayList<>();
        int pointEnd = -1;

        public Param(int start, char tag) {
            this.start = start;
            this.tag = tag;
        }
    }
}
